package com.qipa.utils;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 日期工具类
 *
 * 日期获取、获取年或月或日、获取日期的格式、获取年月日、获取时分秒【get】
 * 增加减、【add】
 * 转换格式转化（日期转string、string转日期、string转string）、
 * 日期之差、【diff】
 * 年头年尾、月头月尾、周头周尾、周开始和结尾、日开始和结尾、月开始和结尾、【getFirst、getLast】
 * 凌晨weeHours 00:00:00或者23:59:59
 * </p>
 */
public class DateUtils {

	private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>();

	private static final Object object = new Object();

	/**
	 * 获取系统当前时间
	 *
	 * @return
	 */
	public static Date getCurrentTS() {
		Calendar calendar = Calendar.getInstance();
		return calendar.getTime();
	}

	/**
	 * 获取SimpleDateFormat
	 *
	 * @param pattern 日期格式
	 * @return SimpleDateFormat对象
	 * @throws RuntimeException 异常：非法日期格式
	 */
	private static SimpleDateFormat getDateFormat(String pattern) throws RuntimeException {
		SimpleDateFormat dateFormat = threadLocal.get();
		if (dateFormat == null) {
			synchronized (object) {
				if (dateFormat == null) {
					dateFormat = new SimpleDateFormat(pattern);
					dateFormat.setLenient(false);
					threadLocal.set(dateFormat);
				}
			}
		}
		dateFormat.applyPattern(pattern);
		return dateFormat;
	}

	/**
	 * 获取日期中的某数值。
	 * 如获取月份
	 *
	 * @param date     日期
	 * @param dateType 日期格式
	 *                 Calendar.YEAR
	 *                 Calendar.MONTH
	 * @return 数值
	 */
	private static int getInteger(Date date, int dateType) {
		int num = 0;
		Calendar calendar = Calendar.getInstance();
		if (date != null) {
			calendar.setTime(date);
			num = calendar.get(dateType);
		}
		return num;
	}

	/**
	 * 增加日期中某类型的某数值。如增加日期
	 * 增加年份，增加月份
	 *
	 * @param date     日期字符串
	 * @param dateType 类型
	 *                 Calendar.YEAR
	 *                 Calendar.MONTH
	 * @param amount   数值
	 * @return 计算后日期字符串
	 */
	private static String addInteger(String date, int dateType, int amount) {
		String dateString = null;
		DateStyle dateStyle = getDateStyle(date);
		if (dateStyle != null) {
			Date myDate = stringToDate(date, dateStyle);
			myDate = addInteger(myDate, dateType, amount);
			dateString = dateToString(myDate, dateStyle);
		}
		return dateString;
	}

	/**
	 * 增加日期中某类型的某数值。如增加日期
	 *
	 * @param date     日期
	 * @param dateType 类型
	 * @param amount   数值
	 * @return 计算后日期
	 */
	private static Date addInteger(Date date, int dateType, int amount) {
		Date myDate = null;
		if (date != null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.add(dateType, amount);
			myDate = calendar.getTime();
		}
		return myDate;
	}


	/**
	 * 将日期字符串转化为日期。失败返回null。
	 *
	 * @param date    日期字符串
	 * @param pattern 日期格式
	 * @return 日期
	 */
	public static Date stringToDate(String date, String pattern) {
		Date myDate = null;
		if (date != null) {
			try {
				myDate = getDateFormat(pattern).parse(date);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return myDate;
	}

	/**
	 * 通过多个时间戳得到一直精准的日期
	 * 获取精确的日期
	 * 这个方法是给下面获取日期格式那个方法用的
	 *
	 * @param timestamps 时间long集合
	 * @return 日期
	 */
	private static Date getAccurateDate(List<Long> timestamps) {
		Date date = null;
		long timestamp = 0;
		Map<Long, long[]> map = new HashMap<Long, long[]>();
		List<Long> absoluteValues = new ArrayList<Long>();

		if (timestamps != null && timestamps.size() > 0) {
			if (timestamps.size() > 1) {
				for (int i = 0; i < timestamps.size(); i++) {
					for (int j = i + 1; j < timestamps.size(); j++) {
						long absoluteValue = Math.abs(timestamps.get(i) - timestamps.get(j));
						absoluteValues.add(absoluteValue);
						long[] timestampTmp = {timestamps.get(i), timestamps.get(j)};
						map.put(absoluteValue, timestampTmp);
					}
				}

				// 有可能有相等的情况。如2012-11和2012-11-01。时间戳是相等的。此时minAbsoluteValue为0
				// 因此不能将minAbsoluteValue取默认值0
				long minAbsoluteValue = -1;
				if (!absoluteValues.isEmpty()) {
					minAbsoluteValue = absoluteValues.get(0);
					for (int i = 1; i < absoluteValues.size(); i++) {
						if (minAbsoluteValue > absoluteValues.get(i)) {
							minAbsoluteValue = absoluteValues.get(i);
						}
					}
				}

				if (minAbsoluteValue != -1) {
					long[] timestampsLastTmp = map.get(minAbsoluteValue);

					long dateOne = timestampsLastTmp[0];
					long dateTwo = timestampsLastTmp[1];
					if (absoluteValues.size() > 1) {
						timestamp = Math.abs(dateOne) > Math.abs(dateTwo) ? dateOne : dateTwo;
					}
				}
			} else {
				timestamp = timestamps.get(0);
			}
		}

		if (timestamp != 0) {
			date = new Date(timestamp);
		}
		return date;
	}

	/**
	 * 判断字符串是否为日期字符串
	 * 是否是日期
	 * @param date 日期字符串
	 * @return true or false
	 */
	public static boolean isDate(String date) {
		boolean isDate = false;
		if (date != null) {
			if (getDateStyle(date) != null) {
				isDate = true;
			}
		}
		return isDate;
	}

	/**
	 * 获取日期字符串的日期风格。失敗返回null。
	 *
	 * @param date 日期字符串
	 * @return 日期风格
	 */
	public static DateStyle getDateStyle(String date) {
		DateStyle dateStyle = null;
		Map<Long, DateStyle> map = new HashMap<Long, DateStyle>();
		//所有时间格式的时间戳
		List<Long> timestamps = new ArrayList<Long>();
		//循环所有的时间格式，组装map，时间戳为key，样式为value
		for (DateStyle style : DateStyle.values()) {
			if (style.isShowOnly()) {
				continue;
			}
			Date dateTmp = null;
			if (date != null) {
				try {
					ParsePosition pos = new ParsePosition(0);
					dateTmp = getDateFormat(style.getValue()).parse(date, pos);
					if (pos.getIndex() != date.length()) {
						dateTmp = null;
					}
				} catch (Exception e) {
				}
			}
			if (dateTmp != null) {
				timestamps.add(dateTmp.getTime());
				map.put(dateTmp.getTime(), style);
			}
		}
		Date accurateDate = getAccurateDate(timestamps);
		if (accurateDate != null) {
			dateStyle = map.get(accurateDate.getTime());
		}
		return dateStyle;
	}

	/**
	 * 将日期字符串转化为日期。失败返回null。
	 *
	 * @param date 日期字符串
	 * @return 日期
	 */
	public static Date stringToDate(String date) {
		DateStyle dateStyle = getDateStyle(date);
		return stringToDate(date, dateStyle);
	}



	/**
	 * 将日期字符串转化为日期。失败返回null。
	 *
	 * @param date      日期字符串
	 * @param dateStyle 日期风格
	 * @return 日期
	 */
	public static Date stringToDate(String date, DateStyle dateStyle) {
		Date myDate = null;
		if (dateStyle != null) {
			myDate = stringToDate(date, dateStyle.getValue());
		}
		return myDate;
	}


	/**
	 * 日开始和结尾
	 *
	 * @param date
	 * @return
	 * @flag 0 返回yyyy-MM-dd 00:00:00日期<br>
	 * 1 返回yyyy-MM-dd 23:59:59日期
	 */
	public static String weeHours(Date date, int flag) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int hour = cal.get(Calendar.HOUR_OF_DAY);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
		//时分秒（毫秒数）
		long millisecond = hour * 60 * 60 * 1000 + minute * 60 * 1000 + second * 1000;
		//凌晨00:00:00
		cal.setTimeInMillis(cal.getTimeInMillis() - millisecond);

		if (flag == 0) {
			getDateToString(cal.getTime(), DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
		} else if (flag == 1) {
			//凌晨23:59:59
			cal.setTimeInMillis(cal.getTimeInMillis() + 23 * 60 * 60 * 1000 + 59 * 60 * 1000 + 59 * 1000);
		}
		return getDateToString(cal.getTime(), DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
	}


	/**
	 * 日开始和结尾
	 *
	 * @param date
	 * @return
	 * @flag 0 返回yyyy-MM-dd 00:00:00日期<br>
	 * 1 返回yyyy-MM-dd 23:59:59日期
	 */
	public static Date weeHoursDate(Date date, int flag) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int hour = cal.get(Calendar.HOUR_OF_DAY);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
		//时分秒（毫秒数）
		long millisecond = hour * 60 * 60 * 1000 + minute * 60 * 1000 + second * 1000;
		//凌晨00:00:00
		cal.setTimeInMillis(cal.getTimeInMillis() - millisecond);

		if (flag == 0) {
			return cal.getTime();
		} else if (flag == 1) {
			//凌晨23:59:59
			cal.setTimeInMillis(cal.getTimeInMillis() + 23 * 60 * 60 * 1000 + 59 * 60 * 1000 + 59 * 1000);
		}
		return cal.getTime();
	}


	/**
	 * 获得本周一与当前日期相差的天数
	 * 这个方法给下面方法用的
	 * @return
	 */
	public static int getMondayPlus() {
		Calendar cd = Calendar.getInstance();
		int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
		if (dayOfWeek == 1) {
			return -6;
		} else {
			return 2 - dayOfWeek;
		}
	}

	/**
	 * 周开始和结尾
	 * 获得当前周一
	 * @return
	 */
	public static String getCurrentMonday() {
		int mondayPlus = getMondayPlus();
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.add(GregorianCalendar.DATE, mondayPlus);
		Date monday = currentDate.getTime();
		DateFormat df = DateFormat.getDateInstance();
		String preMonday = df.format(monday);
		return preMonday;
	}

	/**
	 * 周开始和结尾
	 * 获得当前周一
	 * @return
	 */
	public static Date getCurrentMondayDate() {
		int mondayPlus = getMondayPlus();
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.add(GregorianCalendar.DATE, mondayPlus);
		Date monday = currentDate.getTime();
		return monday;
	}


	/**
	 * 周开始和结尾
	 * 获得当前周日
	 * @return
	 */
	public static String getPreviousSunday() {
		int mondayPlus = getMondayPlus();
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.add(GregorianCalendar.DATE, mondayPlus + 6);
		Date monday = currentDate.getTime();
		DateFormat df = DateFormat.getDateInstance();
		String preMonday = df.format(monday);
		return preMonday;
	}

	/**
	 * 周开始和结尾
	 * 获得当前周日
	 * @return
	 */
	public static Date getPreviousSundayDate() {
		int mondayPlus = getMondayPlus();
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.add(GregorianCalendar.DATE, mondayPlus + 6);
		Date monday = currentDate.getTime();
		return monday;
	}


	/**
	 * 将日期转化为日期字符串。失败返回null。
	 *
	 * @param date    日期
	 * @param pattern 日期格式
	 * @return 日期字符串
	 */
	public static String dateToString(Date date, String pattern) {
		String dateString = null;
		if (date != null) {
			try {
				dateString = getDateFormat(pattern).format(date);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return dateString;
	}

	/**
	 * 将日期转化为日期字符串。失败返回null。
	 *
	 * @param date      日期
	 * @param dateStyle 日期风格
	 * @return 日期字符串
	 */
	public static String dateToString(Date date, DateStyle dateStyle) {
		String dateString = null;
		if (dateStyle != null) {
			dateString = dateToString(date, dateStyle.getValue());
		}
		return dateString;
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date       旧日期字符串
	 * @param newPattern 新日期格式
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, String newPattern) {
		DateStyle oldDateStyle = getDateStyle(date);
		return stringToString(date, oldDateStyle, newPattern);
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date         旧日期字符串
	 * @param newDateStyle 新日期风格
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, DateStyle newDateStyle) {
		DateStyle oldDateStyle = getDateStyle(date);
		return stringToString(date, oldDateStyle, newDateStyle);
	}

	/**
	 * date装date，换格式
	 * @param date
	 * @param dateStyle
	 * @return
	 */
	public static Date dateToDate(Date date, String dateStyle) {
		String dateToString = getDateToString(date, dateStyle);
		Date date1 = stringToDate(dateToString, dateStyle);
		return date1;
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date        旧日期字符串
	 * @param olddPattern 旧日期格式
	 * @param newPattern  新日期格式
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, String olddPattern, String newPattern) {
		return dateToString(stringToDate(date, olddPattern), newPattern);
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date         旧日期字符串
	 * @param olddDteStyle 旧日期风格
	 * @param newParttern  新日期格式
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, DateStyle olddDteStyle, String newParttern) {
		String dateString = null;
		if (olddDteStyle != null) {
			dateString = stringToString(date, olddDteStyle.getValue(), newParttern);
		}
		return dateString;
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date         旧日期字符串
	 * @param olddPattern  旧日期格式
	 * @param newDateStyle 新日期风格
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, String olddPattern, DateStyle newDateStyle) {
		String dateString = null;
		if (newDateStyle != null) {
			dateString = stringToString(date, olddPattern, newDateStyle.getValue());
		}
		return dateString;
	}

	/**
	 * 将日期字符串转化为另一日期字符串。失败返回null。
	 *
	 * @param date         旧日期字符串
	 * @param olddDteStyle 旧日期风格
	 * @param newDateStyle 新日期风格
	 * @return 新日期字符串
	 */
	public static String stringToString(String date, DateStyle olddDteStyle, DateStyle newDateStyle) {
		String dateString = null;
		if (olddDteStyle != null && newDateStyle != null) {
			dateString = stringToString(date, olddDteStyle.getValue(), newDateStyle.getValue());
		}
		return dateString;
	}

	/**
	 * 获取日期的时分秒
	 * 00:00:00
	 * @param dateTime
	 * @return
	 */
	public static String getHourMinuteSecond(String dateTime) {
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat(DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
			Calendar calendar = Calendar.getInstance();
			Date parse = dateFormat.parse(dateTime);
			calendar.setTime(parse);
			return calendar.get(Calendar.HOUR_OF_DAY) + ":" +
					calendar.get(Calendar.MINUTE) + ":" +
					calendar.get(Calendar.SECOND);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}


	/**
	 * 增加日期的年份。失败返回null。
	 *
	 * @param date       日期
	 * @param yearAmount 增加数量。可为负数
	 * @return 增加年份后的日期字符串
	 */
	public static String addYear(String date, int yearAmount) {
		return addInteger(date, Calendar.YEAR, yearAmount);
	}

	/**
	 * 增加日期的年份。失败返回null。
	 *
	 * @param date       日期
	 * @param yearAmount 增加数量。可为负数
	 * @return 增加年份后的日期
	 */
	public static Date addYear(Date date, int yearAmount) {
		return addInteger(date, Calendar.YEAR, yearAmount);
	}

	/**
	 * 增加日期的月份。失败返回null。
	 *
	 * @param date        日期
	 * @param monthAmount 增加数量。可为负数
	 * @return 增加月份后的日期字符串
	 */
	public static String addMonth(String date, int monthAmount) {
		return addInteger(date, Calendar.MONTH, monthAmount);
	}

	/**
	 * 增加日期的月份。失败返回null。
	 *
	 * @param date        日期
	 * @param monthAmount 增加数量。可为负数
	 * @return 增加月份后的日期
	 */
	public static Date addMonth(Date date, int monthAmount) {
		return addInteger(date, Calendar.MONTH, monthAmount);
	}

	/**
	 * 增加日期的天数。失败返回null。
	 *
	 * @param date      日期字符串
	 * @param dayAmount 增加数量。可为负数
	 * @return 增加天数后的日期字符串
	 */
	public static String addDay(String date, int dayAmount) {
		return addInteger(date, Calendar.DATE, dayAmount);
	}


	/**
	 * 增加日期的天数。失败返回null。
	 *
	 * @param date      日期
	 * @param dayAmount 增加数量。可为负数
	 * @return 增加天数后的日期
	 */
	public static Date addDay(Date date, int dayAmount) {
		return addInteger(date, Calendar.DATE, dayAmount);
	}

	/**
	 * 增加日期的小时。失败返回null。
	 *
	 * @param date       日期字符串
	 * @param hourAmount 增加数量。可为负数
	 * @return 增加小时后的日期字符串
	 */
	public static String addHour(String date, int hourAmount) {
		return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount);
	}

	/**
	 * 增加日期的小时。失败返回null。
	 *
	 * @param date       日期
	 * @param hourAmount 增加数量。可为负数
	 * @return 增加小时后的日期
	 */
	public static Date addHour(Date date, int hourAmount) {
		return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount);
	}

	/**
	 * 增加日期的分钟。失败返回null。
	 *
	 * @param date         日期字符串
	 * @param minuteAmount 增加数量。可为负数
	 * @return 增加分钟后的日期字符串
	 */
	public static String addMinute(String date, int minuteAmount) {
		return addInteger(date, Calendar.MINUTE, minuteAmount);
	}

	/**
	 * 增加日期的分钟。失败返回null。
	 *
	 * @param date         日期
	 * @param minuteAmount 增加数量。可为负数
	 * @return 增加分钟后的日期
	 */
	public static Date addMinute(Date date, int minuteAmount) {
		return addInteger(date, Calendar.MINUTE, minuteAmount);
	}

	/**
	 * 增加日期的秒钟。失败返回null。
	 *
	 * @param date         日期字符串
	 * @param secondAmount 增加数量。可为负数
	 * @return 增加秒钟后的日期字符串
	 */
	public static String addSecond(String date, int secondAmount) {
		return addInteger(date, Calendar.SECOND, secondAmount);
	}

	/**
	 * 增加日期的秒钟。失败返回null。
	 *
	 * @param date         日期
	 * @param secondAmount 增加数量。可为负数
	 * @return 增加秒钟后的日期
	 */
	public static Date addSecond(Date date, int secondAmount) {
		return addInteger(date, Calendar.SECOND, secondAmount);
	}

	/**
	 * 获取日期的年份。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 年份
	 */
	public static int getYear(String date) {
		return getYear(stringToDate(date));
	}

	/**
	 * 获取日期的年份。失败返回0。
	 *
	 * @param date 日期
	 * @return 年份
	 */
	public static int getYear(Date date) {
		return getInteger(date, Calendar.YEAR);
	}

	/**
	 * 获取日期的月份。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 月份
	 */
	public static int getMonth(String date) {
		return getMonth(stringToDate(date));
	}

	/**
	 * 获取日期的月份。失败返回0。
	 *
	 * @param date 日期
	 * @return 月份
	 */
	public static int getMonth(Date date) {
		return getInteger(date, Calendar.MONTH) + 1;
	}

	/**
	 * 获取日期的天数。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 天
	 */
	public static int getDay(String date) {
		return getDay(stringToDate(date));
	}

	/**
	 * 获取日期的天数。失败返回0。
	 *
	 * @param date 日期
	 * @return 天
	 */
	public static int getDay(Date date) {
		return getInteger(date, Calendar.DATE);
	}

	/**
	 * 获取日期的小时。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 小时
	 */
	public static int getHour(String date) {
		return getHour(stringToDate(date));
	}

	/**
	 * 获取日期的小时。失败返回0。
	 *
	 * @param date 日期
	 * @return 小时
	 */
	public static int getHour(Date date) {
		return getInteger(date, Calendar.HOUR_OF_DAY);
	}

	/**
	 * 获取日期的分钟。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 分钟
	 */
	public static int getMinute(String date) {
		return getMinute(stringToDate(date));
	}

	/**
	 * 获取日期的分钟。失败返回0。
	 *
	 * @param date 日期
	 * @return 分钟
	 */
	public static int getMinute(Date date) {
		return getInteger(date, Calendar.MINUTE);
	}

	/**
	 * 获取日期的秒钟。失败返回0。
	 *
	 * @param date 日期字符串
	 * @return 秒钟
	 */
	public static int getSecond(String date) {
		return getSecond(stringToDate(date));
	}

	/**
	 * 获取日期的秒钟。失败返回0。
	 *
	 * @param date 日期
	 * @return 秒钟
	 */
	public static int getSecond(Date date) {
		return getInteger(date, Calendar.SECOND);
	}

	/**
	 * 获取日期 。默认yyyy-MM-dd格式。失败返回null。
	 *
	 * @param date 日期字符串
	 * @return 日期
	 */
	public static String getDate(String date) {
		return stringToString(date, DateStyle.YYYY_MM_DD);
	}

	/**
	 * 获取日期。默认yyyy-MM-dd格式。失败返回null。
	 *
	 * @param date 日期
	 * @return 日期
	 */
	public static String getDate(Date date) {
		return dateToString(date, DateStyle.YYYY_MM_DD);
	}

	/**
	 * 获取日期的时间。默认HH:mm:ss格式。失败返回null。
	 *
	 * @param date 日期字符串
	 * @return 时间
	 */
	public static String getTime(String date) {
		return stringToString(date, DateStyle.HH_MM_SS);
	}

	/**
	 * 设置某个日期的日
	 * @param date
	 * @param day
	 * @return
	 */
	public static Date setDaytoDate(Date date, int day) {
		Date myDate = new Date();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		calendar.set(Calendar.DAY_OF_MONTH, day);
		myDate = calendar.getTime();

		return myDate;
	}

	/**
	 * 获取日期的时间部分。默认HH:mm:ss格式。失败返回null。
	 * 获取时分秒
	 * @param date 日期
	 * @return 时间
	 */
	public static String getTime(Date date) {
		return dateToString(date, DateStyle.HH_MM_SS);
	}

	/**
	 * 日开始和结尾
	 * 获得给定时间num天后的转钟时间
	 * 2019-01-11 00:00:00
	 * @param num
	 * @param date
	 * @return
	 */
	public static Calendar getZeroTime(int num, Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + num);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal;
	}

	/**
	 * 日开始和结尾
	 * 计算零点时间
	 *
	 * @param date 预计获得零点时间
	 * @return Date
	 */
	public static Date getDeadLineTime(Date date) {
		return getZeroTime(0, date).getTime();
	}

	/**
	 * 日开始和结尾
	 * 计算零点时间
	 *
	 * @param date 预计获得零点时间
	 * @param num  预计时间增加天数
	 * @return Date
	 */
	public static Date getDeadLineTime(int num, Date date) {
		return getZeroTime(num, date).getTime();
	}

	/**
	 * 获取两个日期差
	 * 相差天数
	 * @param startDate
	 * @param endDate
	 * @return Long 返回天数 （精确到天数）
	 */
	public static Long diffDays(Date startDate, Date endDate) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			startDate = sdf.parse(sdf.format(startDate));
			endDate = sdf.parse(sdf.format(endDate));
			Calendar cal = Calendar.getInstance();
			cal.setTime(startDate);
			long time1 = cal.getTimeInMillis();
			cal.setTime(endDate);
			long time2 = cal.getTimeInMillis();
			long between_days = (time2 - time1) / (1000 * 3600 * 24);
			return between_days;
		} catch (ParseException e) {
			// 不做任何操作("getDaysSub error!", e);
			return 0L;
		}

	}


	/**
	 * 获取两个日期之间相差的 天 时 分
	 * @param startTime
	 * @param endTime
	 * @param format
	 * @return
	 */
	public static Map<String,Long> dayDiff(String startTime, String endTime, String format){
		Map<String,Long> map = new HashMap<String,Long>();
		long day = 0;
		long hour = 0;
		long min = 0;
		long sec = 0;
		try{
			//按照传入的格式生成一个simpledateformate对象
			SimpleDateFormat sd = new SimpleDateFormat(format);
			long nd = 1000*24*60*60;//一天的毫秒数
			long nh = 1000*60*60;//一小时的毫秒数
			long nm = 1000*60;//一分钟的毫秒数
			long ns = 1000;//一秒钟的毫秒数long diff;try {
			//获得两个时间的毫秒时间差异
			long diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime();
			day = diff/nd;//计算差多少天
			hour = diff%nd/nh;//计算差多少小时
			min = diff%nd%nh/nm;//计算差多少分钟
			sec = diff%nd%nh%nm/ns;//计算差多少秒//输出结果
		}catch(Exception e){
			e.printStackTrace();
		}
		map.put("day", day);
		map.put("hour", hour);
		map.put("min", min);
		map.put("sec", sec);
		return map;
	}

	/**
	 * @return Long 返回类型
	 * @throws
	 * @Title: getRemainingSeconds
	 * @Description: <p>
	 * 当前时间与当前下一天零点的时间差（秒）
	 * <p>
	 * @Author jiajunjun
	 */
	public static int getRemainingSeconds() {
		Calendar curDate = Calendar.getInstance();
		Calendar tommorowDate = new GregorianCalendar(curDate.get(Calendar.YEAR), curDate.get(Calendar.MONTH),
				curDate.get(Calendar.DATE) + 1, 0, 0, 0);
		int seconds = (int) ((tommorowDate.getTimeInMillis() - curDate.getTimeInMillis()) / 1000);
		return seconds;
	}

	/**
	 * 月头月尾
	 * 获取当前月最后一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getLastDayByMonth(Date date) {
		return getLastDayByMonth(date, 0);
	}

	/**
	 * <p>
	 * 月头月尾
	 * 得到给定时间增加n个月的月最后一天
	 * <p>
	 *
	 * @param date     具体时间
	 * @param addMonth 时间增肌月份
	 * @Title getLastDate
	 */
	public static Date getLastDayByMonth(Date date, int addMonth) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.MONTH, addMonth);// 加1个月
		int value = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, value);
		return c.getTime();
	}


	/**
	 * <p>
	 * 月头月尾
	 * 得到给定时间增加n个月的月第一天
	 * <p>
	 *
	 * @param date     具体时间
	 * @param addMonth 时间增肌月份
	 * @Title getFirstDate
	 */
	public static Date getFirstDayByMonth(Date date, int addMonth) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.MONTH, addMonth);// 加1个月
		int value = c.getActualMinimum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, value);
		return c.getTime();
	}


	/**
	 * <p>
	 *     年头年尾
	 * 得到给定时间增加n个年的年第一天
	 * <p>
	 *
	 * @param date    具体时间
	 * @param addYear 时间增加年份
	 * @Title getYearFirstDate
	 */
	public static Date getYearFirstDate(Date date, int addYear) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.YEAR, addYear);// 加年
		int value = c.getActualMinimum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, value);//设置月第一天
		c.set(Calendar.MONTH, 0);//设置月为1月
		return c.getTime();
	}


	/**
	 * <p>
	 *     年头年尾
	 * 得到给定时间增加n个年的年最后一天
	 * <p>
	 *
	 * @param date    具体时间
	 * @param addYear 时间增加年份
	 * @Title getYearLastDate
	 */
	public static Date getYearLastDate(Date date, int addYear) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.YEAR, addYear);// 加1个月
		int value = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, value);//设置月最后天
		int value2 = c.getActualMaximum(Calendar.MONTH);
		c.set(Calendar.MONTH, value2);//设置月为1月
		return c.getTime();
	}


	/**
	 * 获取当前月第一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getFirstDayByMonth(Date date) {
		return getFirstDayByMonth(date, 0);
	}

	/**
	 * 获取当前日期的前几天
	 *
	 * @param date 日期
	 * @param day  提前天数
	 * @return
	 */
	public static Date getPreDate(Date date, int day) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.DATE, -1);
		return c.getTime();
	}

	/**
	 * <p>
	 * 计算两个时间相差的所有月份
	 * <p>
	 *
	 * @param bigDate   较大的时间
	 * @param youngDate 较小的时间
	 * @return INT 返回类型
	 * @throws
	 * @Title calculateMonthIn
	 */
	public static int diffMonthIn(Date bigDate, Date youngDate) {
		if (bigDate == null || youngDate == null)
			throw new IllegalArgumentException("param error!");

		int months = 0;
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(bigDate);
		c2.setTime(youngDate);
		int years = c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR);
		months = c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
		return months + years * 12;
	}

	/**
	 * 日开始和结尾
	 * 返回下一个最近的0点时刻。例如当前时间是1日12：35分，则返回2日0时0分0秒
	 *
	 * @param currentTime 指定时间
	 * @return null if currentTime is null
	 */
	public static Date getMidnight(Date currentTime) {
		if (currentTime != null) {
			Calendar c = Calendar.getInstance();
			c.setTime(currentTime);
			c.set(Calendar.HOUR_OF_DAY, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			c.set(Calendar.MILLISECOND, 0);
			c.add(Calendar.DATE, 1);
			return c.getTime();
		}
		return null;
	}


	/**
	 * 日开始和结尾
	 * 获取给定日期的0点时刻
	 * @param currentTime
	 * @return
	 */
	public static Date getCurrentMidnight(Date currentTime) {
		if (currentTime != null) {
			Calendar c = Calendar.getInstance();
			c.setTime(currentTime);
			c.set(Calendar.HOUR_OF_DAY, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			c.set(Calendar.MILLISECOND, 0);
			return c.getTime();
		}
		return null;
	}

	/**
	 * 两个日期相差多少分钟
	 *
	 * @param startTime
	 * @return
	 */
	public static Long dateDiffMinute(Date startTime) {
		long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
		long nh = 1000 * 60 * 60;// 一小时的毫秒数
		long nm = 1000 * 60;// 一分钟的毫秒数
		Long diff = new Date().getTime() - startTime.getTime();
		long min = diff % nd % nh / nm;// 计算差多少分钟
		return min;
	}

	/**
	 * 两个日期相差的天数
	 *
	 * @param
	 * @return
	 */
	public static long differDays(Date before, Date after) {
		long t = after.getTime() - before.getTime();
		return t / (24 * 60 * 60 * 1000);
	}


	/**
	 *
	 * 获取两个日期之间相差的 天时 分
	 * 【24小时，不满24小时不算一天】
	 * @param startTime
	 * @param endTime
	 * @param dateType 1天 2小时 3分钟 4秒
	 * @return
	 */
	public static Long diffDayOrHourOrMinOrSec(String startTime, String endTime, int dateType){
		long day = 0;
		long hour = 0;
		long min = 0;
		long sec = 0;
		try{
			//按照传入的格式生成一个simpledateformate对象
			SimpleDateFormat sd = new SimpleDateFormat(DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
			long nd = 1000*24*60*60;//一天的毫秒数
			long nh = 1000*60*60;//一小时的毫秒数
			long nm = 1000*60;//一分钟的毫秒数
			long ns = 1000;//一秒钟的毫秒数long diff;try {
			//获得两个时间的毫秒时间差异
			long diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime();
			day = diff/nd;//计算差多少天
			hour = diff%nd/nh;//计算差多少小时
			min = diff%nd%nh/nm;//计算差多少分钟
			sec = diff%nd%nh%nm/ns;//计算差多少秒//输出结果
		}catch(Exception e){
			e.printStackTrace();
		}
		if(1 == dateType){
			return day;
		}else if(2 == dateType){
			return hour;
		}else if(3 == dateType){
			return min;
		}else{
			return sec;
		}
	}


	/**
	 *
	 * 获取两个日期之间相差的 天时 分
	 * 【24小时，不满24小时不算一天】
	 * @param startTime
	 * @param endTime
	 * @param dateType 1天 2小时 3分钟 4秒
	 * @return
	 */
	public static Long diffDayOrHourOrMinOrSecByDate(Date startTime, Date endTime, int dateType){
		long day = 0;
		long hour = 0;
		long min = 0;
		long sec = 0;
		try{
			//按照传入的格式生成一个simpledateformate对象
			SimpleDateFormat sd = new SimpleDateFormat(DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
			long nd = 1000*24*60*60;//一天的毫秒数
			long nh = 1000*60*60;//一小时的毫秒数
			long nm = 1000*60;//一分钟的毫秒数
			long ns = 1000;//一秒钟的毫秒数long diff;try {
			//获得两个时间的毫秒时间差异
			long diff = endTime.getTime() - startTime.getTime();
			day = diff/nd;//计算差多少天
			hour = diff%nd/nh;//计算差多少小时
			min = diff%nd%nh/nm;//计算差多少分钟
			sec = diff%nd%nh%nm/ns;//计算差多少秒//输出结果
		}catch(Exception e){
			e.printStackTrace();
		}
		if(1 == dateType){
			return day;
		}else if(2 == dateType){
			return hour;
		}else if(3 == dateType){
			return min;
		}else{
			return sec;
		}
	}

	/**
	 * 返回系统当前时间对应的次日0时。例如当前时间是1日12：35分，则返回2日0时0分0秒
	 */
	public static Date getMidnight() {
		return getMidnight(new Date());
	}

	/**
	 * date转string
	 * @param date
	 * @param format
	 * @return
	 */
	public static String getDateToString(Date date, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	/**
	 * 获取某年某月的第一天
	 * @param year
	 * @param month
	 * @return
	 */
	public static String getFirstDayOfYearMonth(int year, int month) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal_1 = Calendar.getInstance();
		cal_1.set(Calendar.YEAR, year);
		cal_1.set(Calendar.MONTH, month - 1);
		cal_1.set(Calendar.DAY_OF_MONTH, 1);
		String firstDay = format.format(cal_1.getTime());
		return firstDay;
	}


	/**
	 * 这个月第一天
	 * @return
	 */
	public static String getFirstDayOfCalendar() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal_1 = Calendar.getInstance();
		cal_1.set(Calendar.DAY_OF_MONTH, 1);
		String firstDay = format.format(cal_1.getTime());
		return firstDay;
	}

	/**
	 * 获取某年某月的第一天
	 * @param year
	 * @param month
	 * @return
	 */
	public static String getEndDayOfYearMonth(int year, int month) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal_1 = Calendar.getInstance();
		cal_1.set(Calendar.YEAR, year);
		cal_1.set(Calendar.MONTH, month - 1);
		cal_1.set(Calendar.DAY_OF_MONTH, cal_1.getActualMaximum(Calendar.DAY_OF_MONTH));
		String endDay = format.format(cal_1.getTime());
		return endDay;
	}


	/**
	 * string时间转时间戳long
	 *
	 * @param date
	 * @return
	 */
	public static long getStringDateToLong(String date) {
		Date date1 = DateUtils.stringToDate(date);
		return date1.getTime();
	}

	/**
	 * 时间戳long转string（13位的long时间戳）
	 *
	 * @param date 毫秒
	 * @return
	 */
	public static String longToString(Long date) {
		Date date1 = new Date(date);
		return getDateToString(date1, DateStyle.YYYY_MM_DD_HH_MM_SS.getValue());
	}


	/**
	 * 获取上周的开始时间
	 * 返回格式：2018-12-31 00:00:00
	 * @return
	 */
	public static Date getBeginDayOfLastWeek() {
		Date date = new Date();
		if (date == null) {
			return null;
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
		if (dayofweek == 1) {
			dayofweek += 7;
		}
		cal.add(Calendar.DATE, 2 - dayofweek - 7);
		return getDayStartTime(cal.getTime());
	}

	/**
	 * 获取上周的结束时间
	 * @return
	 */
	public static Date getEndDayOfLastWeek() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(getBeginDayOfLastWeek());
		cal.add(Calendar.DAY_OF_WEEK, 6);
		Date weekEndSta = cal.getTime();
		return getDayEndTime(weekEndSta);
	}

	/**
	 * 日开始和结尾
	 * 获取某个日期的开始时间 00:00:00
	 * @param d
	 * @return
	 */
	public static Timestamp getDayStartTime(Date d) {
		Calendar calendar = Calendar.getInstance();
		if (null != d) calendar.setTime(d);
		calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return new Timestamp(calendar.getTimeInMillis());
	}

	/**
	 * 日开始和结尾
	 * 获取某个日期的结束时间
	 * @param d
	 * @return
	 */
	public static Timestamp getDayEndTime(Date d) {
		Calendar calendar = Calendar.getInstance();
		if (null != d) calendar.setTime(d);
		calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		return new Timestamp(calendar.getTimeInMillis());
	}


	/**
	 * 周开始和结尾的日期
	 * 时分秒不准
	 * @param data
	 * @param format 格式YYYY-MM-DD
	 * @return
	 */
	public static String getFirstAndLastOfWeek(Date data, String format) {
		Calendar cal = Calendar.getInstance();

		cal.setTime(data);

		int d = 0;
		if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
			d = -6;
		} else {
			d = 2 - cal.get(Calendar.DAY_OF_WEEK);
		}
		cal.add(Calendar.DAY_OF_WEEK, d);
		// 所在周开始日期
		String data1 = new SimpleDateFormat(format).format(cal.getTime());
		cal.add(Calendar.DAY_OF_WEEK, 6);
		// 所在周结束日期
		String data2 = new SimpleDateFormat(format).format(cal.getTime());
		return data1 + "," + data2;

	}

	public static void main(String[] args) throws Exception {
		Date start = addMinute(new Date(), -1);
		SimpleDateFormat df = new SimpleDateFormat(DateStyle.YYYY_MM_DD_HH_MM.getValue());
		System.out.println(df.format(start) + ":00");
		System.out.println(df.format(start) + ":59");

		System.out.println(getTime(new Date()));
		System.out.println(dateToString(getZeroTime(1, new Date()).getTime(), DateStyle.YYYY_MM_DD_HH_MM_SS));
		System.out.println(dateToString(getCurrentMidnight(new Date()), DateStyle.YYYY_MM_DD_HH_MM_SS));
		System.out.println(dateToString(getCurrentMidnight(new Date()), DateStyle.YYYY_MM_DD_HH_MM_SS));
		System.out.println(DateUtils.getDateToString(getFirstDayByMonth(new Date(), 1), DateStyle.YYYY_MM_DD.getValue()));
		System.out.println(getBeginDayOfLastWeek());
		System.out.println(getFirstAndLastOfWeek(new Date(), DateStyle.YYYY_MM_DD_HH_MM.getValue()));

		System.out.println(diffDayOrHourOrMinOrSec("2019-01-01 23:59:59", "2019-01-02 00:00:00", 4));
		System.out.println(diffDayOrHourOrMinOrSec("2019-01-01 23:59:59", "2019-01-02 23:59:59", 1));
		System.out.println(diffDays(DateUtils.stringToDate("2019-01-01 23:59:59"), DateUtils.stringToDate("2019-01-02 00:00:00")));
	}
}